/*
 * Id.java
 *
 * Created on August 11, 2005, 9:54 PM
 *
 * To change this basis, choose Tools | Options and locate the basis under
 * the Source Creation and Management node. Right-click the basis and choose
 * Open. You can then make changes to the basis in the Source Editor.
 */

package com.xucia.jsponic.data;


import java.lang.ref.WeakReference;
import java.util.Map;

import org.mozilla.javascript.BaseFunction;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;

import com.xucia.jsponic.datasource.DataSource;
import com.xucia.jsponic.datasource.QueriableDataSource;
import com.xucia.jsponic.datasource.NewObjectPersister;
import com.xucia.jsponic.remote.StandardJsponFilter.LocalDataSource;
import com.xucia.jsponic.util.StrongSoftSyncHashMap;


/**
 *
 * @author Kris Zyp
 */
public class ObjectId extends Identification<Persistable> {
	protected static Map<String,ObjectId> idMap = new StrongSoftSyncHashMap<String, ObjectId>(100); 
	public final static int DEFAULT_RADIX = 10;
	public static synchronized ObjectId idForString(String value) { 
		ObjectId objId = idMap.get(value);
		if (objId == null) {
			String[] parts;
			parts = value.split("/",2);
			if (parts.length < 2){
				throw new RuntimeException("All ids must be in form of datasource/objectid");
				//objId.source = DataSourceManager.getRootSource();
				//objId.subObjectId = value;
			}
			else
			{
				objId = new ObjectId();
				objId.source = DataSourceManager.getSource(parts[0]);
				objId.subObjectId= parts[1];
			}
			idMap.put(value, objId);
		}
		return objId;
	}
	@Deprecated
	public static void insertObjectForId(String id, Persistable obj) {
		idForString(id).targetRef = new WeakReference<Persistable>(obj);
	}
	@SuppressWarnings("unused")
	public void persistIfNeeded(NewObjectPersister newObjectPersister) {
	}
	public boolean isPersisted() {
		return true;
	}
	public boolean isLocal() {
		return source instanceof LocalDataSource;
	}
	public static synchronized ObjectId idForObject(DataSource source, String objectId) {
		String idAsString = source.getId().length() == 0 ? objectId : source.getId() + '/' + objectId;
		ObjectId objId = idMap.get(idAsString);
		if (objId == null) {
			objId = new ObjectId();
			objId.source = source;
			objId.subObjectId = objectId;
			idMap.put(idAsString,objId);
		}		
		return objId;
	}
	public enum ObjectType {
		Object, Array, Function
	}
	static class LazyObjectId extends ObjectId {
		Class<? extends Lazy> type;

		@Override
		public Persistable resolveTarget() {
				try {
					return (Persistable) type.newInstance();
				} catch (InstantiationException e) {
					throw new RuntimeException(e);
				} catch (IllegalAccessException e) {
					throw new RuntimeException(e);
				}
		}
		
	}
	static class LazyLoadedFunction extends BaseFunction {

		@Override
		public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
			// TODO Auto-generated method stub			
			return super.call(cx, scope, thisObj, args);
		}

		@Override
		public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
			// TODO Auto-generated method stub
			return super.construct(cx, scope, args);
		}

		@Override
		public Scriptable createObject(Context cx, Scriptable scope) {
			// TODO Auto-generated method stub
			return super.createObject(cx, scope);
		}
		
		
	}
	public final static Class<? extends Lazy> LAZY_OBJECT = LazyNativeObject.class;
	public final static Class<? extends Lazy> LAZY_ARRAY = LazyNativeArray.class;
	public final static Class<? extends Lazy> NON_CACHING_OBJECT = NonCachingNativeObject.class;
	public final static Class<? extends Lazy> NON_CACHING_ARRAY = NonCachingNativeArray.class;

	
	
	/**
	 * 
	 * @param source
	 * @param objectId
	 * @param objectType
	 * @return
	 */
/*	public static synchronized ObjectId idForLazyObject(DataSource source, String objectId, ObjectType objectType) {
		return idForLazyObject(source, objectId, objectType == ObjectType.Array ? NativeArray.class : objectType == ObjectType.Function ? LazyLoadedFunction.class : NativeObject.class);
	}*/
	public static synchronized ObjectId idForLazyObject(DataSource source, String objectId, Class<? extends Lazy> objectType) {
		String idAsString = source.getId().length() == 0 ? objectId : source.getId() + '/' + objectId;
		ObjectId objId = idMap.get(idAsString);
		if (objId == null) {
			objId = new LazyObjectId();
			((LazyObjectId) objId).type = objectType; 
			objId.source = source;
			objId.subObjectId = objectId;
			idMap.put(idAsString,objId);
		}		
		return objId;
	}
	protected ObjectId() {
	}
	public void assignId(DataSource source, String objectId) {
		if (source != null)
			throw new RuntimeException("Can not assign an id to object that already exists");
		this.source = source;
		this.subObjectId = objectId;
		idMap.put(toString(),this);
	}
	/*public ObjectId(String value) {
		String[] parts = value.split("/",2);
		if (parts.length < 2)
			objectId = value;
		else
		{
			source = DataSourceManager.getSource(parts[0]);
			objectId= parts[1];
		}
	}*/
	@Override
	protected Persistable resolveTarget() {
		if (source==null)
			return null;
		return PersistableImpl.mapPersistent(this);
	}
	

    @Override
	public boolean equals(Object obj) {
        if (obj == null)
            return false;
        return toString().equals(obj.toString());
    }

    @Override
	public int hashCode() {
        return toString().hashCode();
    }
    
}
